//=============================================================================

#include <fstream>
#include <windows.h>
#include <gl/gl.h>
#include "../inc/aSkeleton.h"
#include "../inc/aAux.h"

//=============================================================================

using namespace std;

//=============================================================================

aSkeleton::aSkeleton() : factor(10000)
{
  vertexesCount = 0;
}

//=============================================================================

asnRet aSkeleton::asLoadSkeleton(const aString& path, unsigned int vCount)
{
  if (path.asGetLength() <= 0)
    return NULLED_PATH;

  asRemoveSkeletonData();
  vertexesCount = vCount;

  fstream file;

  file.open(path.asGetString(), ios_base::in | ios_base::binary);

  if (!file.is_open())
    return CANT_OPEN_SKELETON_FILE;

  unsigned int tCount, len, i, pCount, j;
  const unsigned int maxStringLength = 1024;
  unsigned int tmpCounter;
  char tmpChar[maxStringLength];
  aItem<aJoint>* tmpJoint;

  file.read((char*)&tCount, sizeof(tCount));
  file.read((char*)&pCount, sizeof(pCount));
  for (i = 0; i < tCount; ++i)
  {
    file.read((char*)&len, sizeof(len));

    if (len == 0)
      continue;

    memset(tmpChar, 0, maxStringLength);
    file.read(tmpChar, len);
    tmpJoint = asGetJointByName(joints.alGetFirstItem(), tmpChar);

    tmpJoint = asAddJoint(tmpJoint);
    tmpJoint->data.weights = new float[pCount*3];

    memset(tmpChar, 0, maxStringLength);
    file.read((char*)&len, sizeof(len));
    file.read(tmpChar, len);
    tmpJoint->data.name = tmpChar;
    file.read((char*)tmpJoint->data.bindMatrix, sizeof(float)*aJoint::matrixSize);
    memcpy(tmpJoint->data.currentMatrix, tmpJoint->data.bindMatrix, sizeof(float)*aJoint::matrixSize);

    for (j = 0; j < pCount*3; ++j)
    {
      file.read((char*)&tmpCounter, sizeof(tmpCounter));
      file.read((char*)&tmpJoint->data.weights[tmpCounter], sizeof(float));
    }
  }
  file.close();

  asGenerateStaticJointsList(joints.alGetFirstItem());
  asCalculatePositionsByBindMatrix(joints.alGetFirstItem());
  asAddFactorToBindPositions();
  asCalculateJoints(joints.alGetFirstItem());
  asCopyDataToCurrentMatrix();

  return FINISH;
}

//=============================================================================

void aSkeleton::asDrawSkeleton(aItem<aJoint>* jnt, bool drawAxis) const
{
  if (!jnt)
    jnt = joints.alGetFirstItem();

  aItem<aJoint>* tmpJoint = jnt;

  while(tmpJoint)
  {
    glColor3ub(255, 0, 255);
    if (tmpJoint->data.parent)
    {
      glBegin(GL_LINES);
        glVertex3f(tmpJoint->data.parent->data.currentMatrix[12], tmpJoint->data.parent->data.currentMatrix[13], tmpJoint->data.parent->data.currentMatrix[14]);
        glVertex3f(tmpJoint->data.currentMatrix[12], tmpJoint->data.currentMatrix[13], tmpJoint->data.currentMatrix[14]);
      glEnd();
    }
    glColor3ub(255, 255, 255);
    glBegin(GL_POINTS);
      glVertex3f(tmpJoint->data.currentMatrix[12], tmpJoint->data.currentMatrix[13], tmpJoint->data.currentMatrix[14]);
    glEnd();
    if (drawAxis)
    {
      glColor3ub(255, 0, 0);
      glBegin(GL_LINES);
        glVertex3f(tmpJoint->data.currentMatrix[12], tmpJoint->data.currentMatrix[13], tmpJoint->data.currentMatrix[14]);
        glVertex3f(tmpJoint->data.currentMatrix[12] + tmpJoint->data.currentMatrix[0], tmpJoint->data.currentMatrix[13] + tmpJoint->data.currentMatrix[1], tmpJoint->data.currentMatrix[14] + tmpJoint->data.currentMatrix[2]);
      glColor3ub(0, 255, 0);
        glVertex3f(tmpJoint->data.currentMatrix[12], tmpJoint->data.currentMatrix[13], tmpJoint->data.currentMatrix[14]);
        glVertex3f(tmpJoint->data.currentMatrix[12] + tmpJoint->data.currentMatrix[4], tmpJoint->data.currentMatrix[13] + tmpJoint->data.currentMatrix[5], tmpJoint->data.currentMatrix[14] + tmpJoint->data.currentMatrix[6]);
      glColor3ub(0, 0, 255);
        glVertex3f(tmpJoint->data.currentMatrix[12], tmpJoint->data.currentMatrix[13], tmpJoint->data.currentMatrix[14]);
        glVertex3f(tmpJoint->data.currentMatrix[12] + tmpJoint->data.currentMatrix[8], tmpJoint->data.currentMatrix[13] + tmpJoint->data.currentMatrix[9], tmpJoint->data.currentMatrix[14] + tmpJoint->data.currentMatrix[10]);
      glEnd();
    }

    if (tmpJoint->data.child.alGetCount() > 0)
      asDrawSkeleton(tmpJoint->data.child.alGetFirstItem(), drawAxis);

    tmpJoint = tmpJoint->next;
  }
}

//=============================================================================

bool aSkeleton::asAddAnimationToJoint(const aString& jntName, const aString& anmName, float* ptr, unsigned int frames)
{
  if ((jntName.asGetLength() <= 0) || (anmName.asGetLength() <= 0) || !ptr)
    return 0;

  aItem<aJoint>* tmpJoint = asGetJointByName(joints.alGetFirstItem(), jntName);

  if (tmpJoint)
  {
    aItem<aAnimationsTrack>* tmpTrack;
    
    tmpTrack = tmpJoint->data.track.alGetFirstItem();
    while(tmpTrack)
    {
      if (tmpTrack->data.caption == anmName)
        break;

      tmpTrack = tmpTrack->next;
    }
    if (!tmpTrack)
    {
      tmpTrack = tmpJoint->data.track.alAddItem();
      tmpTrack->data.mtx = ptr;
      tmpTrack->data.caption = anmName;
      tmpTrack->data.framesCount = frames;
    }
    else
      return 0;

    return 1;
  }

  return 0;
}

//=============================================================================

asnRet aSkeleton::asPrepareAnimation(const aString& name)
{
  if (name.asGetLength() <= 0)
    return NULLED_ANIMATION_NAME;

  long framesCount = (-1);
  aItem<aJoint*>* tmpJoint = pubJoints.alGetFirstItem();
  aItem<aAnimationsTrack>* tmpAnim;

  while(tmpJoint)
  {
    tmpAnim = tmpJoint->data->ajGetAnimationByName(name);
    if (tmpAnim)
    {
      framesCount = tmpAnim->data.framesCount;

      break;
    }
    tmpJoint = tmpJoint->next;
  }

  if (framesCount == (-1))
    return NO_SUCH_ANIMATION_FOUNDED;

  size_t magicSize = sizeof(float)*aJoint::matrixSize;
  long magicSize2, i, j;
  aVector ijk[3], pos;

  for (i = 0; i < framesCount; ++i)
  {
    magicSize2 = i*aJoint::matrixSize;

    tmpJoint = pubJoints.alGetFirstItem();
    while(tmpJoint)
    {
      tmpAnim = tmpJoint->data->ajGetAnimationByName(name);

      if (tmpAnim)
        memcpy(tmpJoint->data->currentMatrix, &tmpAnim->data.mtx[magicSize2], magicSize);
      
      tmpJoint = tmpJoint->next;
    }

    asCalculateJoints();
    asCopyDataToCurrentMatrix();

    tmpJoint = pubJoints.alGetFirstItem();
    while(tmpJoint)
    {
      tmpAnim = tmpJoint->data->ajGetAnimationByName(name);

      if (tmpAnim)
        memcpy(&tmpAnim->data.mtx[magicSize2], tmpJoint->data->currentMatrix, magicSize);

      tmpJoint = tmpJoint->next;
    }
  }

  asResetJointsToBind();
  asCopyDataToCurrentMatrix();

  for (i = 0; i < framesCount; ++i)
  {
    magicSize2 = i*aJoint::matrixSize;

    tmpJoint = pubJoints.alGetFirstItem();
    while(tmpJoint)
    {
      tmpAnim = tmpJoint->data->ajGetAnimationByName(name);

      if (tmpAnim)
      {
        for (j = 0; j < aJoint::matrixSize; ++j)
          if (aAux::aaGetInstance().aaCompareFloatHigh(tmpAnim->data.mtx[magicSize2 + j], tmpJoint->data->currentMatrix[j]))
            ++tmpAnim->data.matrixCalculator;
          else
            break;
      }
      tmpJoint = tmpJoint->next;
    }
  }

  tmpJoint = pubJoints.alGetFirstItem();
  while(tmpJoint)
  {
    tmpAnim = tmpJoint->data->ajGetAnimationByName(name);

    if (tmpAnim)
      if (tmpAnim->data.matrixCalculator >= ((aJoint::matrixSize)*framesCount))
        tmpJoint->data->track.alRemoveItem(tmpAnim);

    tmpJoint = tmpJoint->next;
  }

  return FINISH;
}

//=============================================================================

void aSkeleton::asRemoveSkeletonData()
{
  joints.alRemoveItems();
  pubJoints.alRemoveItems();
  vertexesCount = 0;
}

//=============================================================================

size_t aSkeleton::asGetDataVolume() const
{
  size_t res = 0;
  aItem<aJoint*>* tmpJoint = pubJoints.alGetFirstItem();
  int count = pubJoints.alGetCount();

  if (count <= 0)
    return 0;

  size_t floatSize = sizeof(float);
  size_t charSize = tmpJoint->data->name.asGetCharSize();

  while(tmpJoint)
  {
    if (tmpJoint->data)
    {
      res += tmpJoint->data->name.asGetLength()*charSize;//volume for the names of joints
      if (tmpJoint->data->parent)
        res += tmpJoint->data->parent->data.name.asGetLength()*charSize;//volume for the parent's name
    }
    tmpJoint = tmpJoint->next;
  }
  res += sizeof(vertexesCount)*count;//vertexesCount
  res += sizeof(size_t)*count*2; //volume for the names length values; 2 because tehre is parent name too
  res += floatSize*tmpJoint->data->matrixSize*count;//volume for the bind matrix
  res += floatSize*15*count;//volume for bindIJK[3] & bindIJKValue & bindPosition(current values must be copied from these three)
  res += floatSize*vertexesCount*count;//volume of whole weight

  return res;
}

//=============================================================================
//
//=======DATA FORMAT=======
//
// vertexesCount of surface for skeleton
// length of joint's name
// joint's name
// length of parent joint's name
// parent joint's name
// bindIJK[3]
// bindPosition(x y z)
// bindIJKValue[3]
// bindMatrix[16]
// weights[vertexesCount]
//
//=======DATA FORMAT=======
//

asnRet aSkeleton::asCollectData(void* data, size_t wholeSize) const
{
  if (wholeSize <= 0)
    return COL_BAD_VOLUME_SIZE;

  if (!data)
    return COL_BAD_SKEL_DATA_POINTER;

  int jCount = pubJoints.alGetCount();

  if (jCount <= 0)
    return COL_NO_JOINTS_DATA;

  aItem<aJoint*>* tmpJoint = pubJoints.alGetFirstItem();
  char* tmpPointer = (char*) data;
  size_t shift = 0;
  size_t floatSize = sizeof(float);
  size_t charSize = tmpJoint->data->name.asGetCharSize();
  size_t sizeSize = sizeof(size_t);
  size_t tmpLength;

  while(tmpJoint)
  {
    if (tmpJoint->data)
    {
      memcpy(&tmpPointer[shift], &vertexesCount, sizeof(vertexesCount));
      shift += sizeof(vertexesCount);

      tmpLength = tmpJoint->data->name.asGetLength();
      memcpy(&tmpPointer[shift], &tmpLength, sizeSize);
      shift += sizeSize;

      memcpy(&tmpPointer[shift], tmpJoint->data->name.asGetString(), tmpLength*charSize);
      shift += tmpLength*charSize;

      if (!tmpJoint->data->parent)
      {
        tmpLength = 0;
        memcpy(&tmpPointer[shift], &tmpLength, sizeSize);
        shift += sizeSize;
      }
      else
      {
        tmpLength = tmpJoint->data->parent->data.name.asGetLength();
        memcpy(&tmpPointer[shift], &tmpLength, sizeSize);
        shift += sizeSize;

        memcpy(&tmpPointer[shift], tmpJoint->data->parent->data.name.asGetString(), tmpLength*charSize);
        shift += tmpLength*charSize;
      }

      memcpy(&tmpPointer[shift], &tmpJoint->data->bindIJK[0].x, floatSize);
      shift += floatSize;

      memcpy(&tmpPointer[shift], &tmpJoint->data->bindIJK[0].y, floatSize);
      shift += floatSize;

      memcpy(&tmpPointer[shift], &tmpJoint->data->bindIJK[0].z, floatSize);
      shift += floatSize;

      memcpy(&tmpPointer[shift], &tmpJoint->data->bindIJK[1].x, floatSize);
      shift += floatSize;

      memcpy(&tmpPointer[shift], &tmpJoint->data->bindIJK[1].y, floatSize);
      shift += floatSize;

      memcpy(&tmpPointer[shift], &tmpJoint->data->bindIJK[1].z, floatSize);
      shift += floatSize;

      memcpy(&tmpPointer[shift], &tmpJoint->data->bindIJK[2].x, floatSize);
      shift += floatSize;

      memcpy(&tmpPointer[shift], &tmpJoint->data->bindIJK[2].y, floatSize);
      shift += floatSize;

      memcpy(&tmpPointer[shift], &tmpJoint->data->bindIJK[2].z, floatSize);
      shift += floatSize;

      memcpy(&tmpPointer[shift], &tmpJoint->data->bindPosition.x, floatSize);
      shift += floatSize;

      memcpy(&tmpPointer[shift], &tmpJoint->data->bindPosition.y, floatSize);
      shift += floatSize;

      memcpy(&tmpPointer[shift], &tmpJoint->data->bindPosition.z, floatSize);
      shift += floatSize;

      memcpy(&tmpPointer[shift], &tmpJoint->data->bindIJKValue[0], floatSize*3);
      shift += floatSize*3;

      memcpy(&tmpPointer[shift], &tmpJoint->data->bindMatrix[0], floatSize*tmpJoint->data->matrixSize);
      shift += floatSize*tmpJoint->data->matrixSize;

      memcpy(&tmpPointer[shift], tmpJoint->data->weights, floatSize*vertexesCount);
      shift += floatSize*vertexesCount;
    }
    tmpJoint = tmpJoint->next;

  }

  return FINISH;
}

//=============================================================================

asnRet aSkeleton::asFixTheBones(char* data, int jCount)
{
  if (!data)
    return ABS_BAD_SKELETON_DATA_POINTER;

  if (jCount <= 0)
    return ABS_BAD_SKELETON_JOINTS_COUNT;

  int i = 0;
  aItem<aJoint>* tmpJoint, *tmpJoint2;
  size_t sizeSize = sizeof(size_t);
  size_t tmpLength;
  size_t shift = 0;
  aString tmpString;
  size_t charSize = tmpString.asGetCharSize();
  size_t floatSize = sizeof(float);
  const size_t charBufferSize = 4096;
  wchar_t tmpPointer[charBufferSize];

  for (; i < jCount; ++i)
  {
    tmpJoint = joints.alAddItem();
    memcpy(&vertexesCount, &data[shift], sizeof(vertexesCount));
    shift += sizeof(vertexesCount);

    memcpy(&tmpLength, &data[shift], sizeSize);
    shift += sizeSize;

    memset(tmpPointer, 0, charBufferSize*charSize);
    memcpy(tmpPointer, &data[shift], tmpLength*charSize);
    tmpJoint->data.name = tmpPointer;
    shift += tmpLength*charSize;

    memcpy(&tmpLength, &data[shift], sizeSize);
    shift += sizeSize;
    
    if (tmpLength > 0)
    {
        memset(&tmpPointer[0], 0, charBufferSize);
        memcpy(tmpPointer, &data[shift], tmpLength*charSize);
        tmpJoint2 = asGetJointByName(joints.alGetFirstItem(), tmpPointer);
        if (tmpJoint2)
          tmpJoint->data.parent = tmpJoint2;
        shift += tmpLength*charSize;
    }

    memcpy(&tmpJoint->data.bindIJK[0].x, &data[shift], floatSize);
    shift += floatSize;

    memcpy(&tmpJoint->data.bindIJK[0].y, &data[shift], floatSize);
    shift += floatSize;

    memcpy(&tmpJoint->data.bindIJK[0].z, &data[shift], floatSize);
    shift += floatSize;

    memcpy(&tmpJoint->data.bindIJK[1].x, &data[shift], floatSize);
    shift += floatSize;

    memcpy(&tmpJoint->data.bindIJK[1].y, &data[shift], floatSize);
    shift += floatSize;

    memcpy(&tmpJoint->data.bindIJK[1].z, &data[shift], floatSize);
    shift += floatSize;

    memcpy(&tmpJoint->data.bindIJK[2].x, &data[shift], floatSize);
    shift += floatSize;

    memcpy(&tmpJoint->data.bindIJK[2].y, &data[shift], floatSize);
    shift += floatSize;

    memcpy(&tmpJoint->data.bindIJK[2].z, &data[shift], floatSize);
    shift += floatSize;

    memcpy(&tmpJoint->data.bindPosition.x, &data[shift], floatSize);
    shift += floatSize;

    memcpy(&tmpJoint->data.bindPosition.y, &data[shift], floatSize);
    shift += floatSize;

    memcpy(&tmpJoint->data.bindPosition.z, &data[shift], floatSize);
    shift += floatSize;

    memcpy(&tmpJoint->data.bindIJKValue[0], &data[shift], floatSize*3);
    shift += floatSize*3;

    memcpy(&tmpJoint->data.bindMatrix[0], &data[shift], floatSize*tmpJoint->data.matrixSize);
    memcpy(tmpJoint->data.currentMatrix, tmpJoint->data.bindMatrix, floatSize*aJoint::matrixSize);
    shift += floatSize*tmpJoint->data.matrixSize;

    tmpJoint->data.weights = new float[vertexesCount];

    memcpy(tmpJoint->data.weights, &data[shift], floatSize*vertexesCount);
    shift += floatSize*vertexesCount;
  }

  asGenerateStaticJointsList(joints.alGetFirstItem());
  asCalculatePositionsByBindMatrix(joints.alGetFirstItem());
  asAddFactorToBindPositions();
  asCalculateJoints(joints.alGetFirstItem());
  asCopyDataToCurrentMatrix();

  return FINISH;
}

//=============================================================================

asnRet aSkeleton::asAbsorbAnimations(char* data, aList<aString>& animList)
{
  if (!data)
    return ABS_BAD_ANIM_DATA_POINTER;

  animList.alRemoveItems();

  int i = 0, j, jCount = joints.alGetCount();
  int tmpCount, tmpCount2;
  aString tmpString;
  size_t intSize = sizeof(int);
  size_t sizeSize = sizeof(size_t);
  size_t charSize = tmpString.asGetCharSize();
  size_t floatSize = sizeof(float);
  size_t tmpLength;
  size_t shift = 0;
  const unsigned int charBufferSize = 4096;
  wchar_t tmpName[charBufferSize];
  aItem<aJoint>* tmpJoint;
  aItem<aString>* tmpItem;
  float* tmpPointer;

  for (; i < jCount; ++i)
  {
    memcpy(&tmpLength, &data[shift], sizeSize);
    shift += sizeSize;

    memset(tmpName, 0, charBufferSize*charSize);
    memcpy(tmpName, &data[shift], charSize*tmpLength);
    shift += charSize*tmpLength;

    tmpJoint = asGetJointByName(joints.alGetFirstItem(), tmpName);

    if (!tmpJoint)
      return ABS_NO_SUCH_JOINT_FOR_ANIM;

    memcpy(&tmpCount, &data[shift], intSize);
    shift += intSize;
    
    if (tmpCount > 0)
    {
      for (j = 0; j < tmpCount; ++j)
      {
        memcpy(&tmpCount2, &data[shift], intSize);
        shift += intSize;

        memcpy(&tmpLength, &data[shift], sizeSize);
        shift += sizeSize;

        memset(tmpName, 0, charBufferSize*charSize);
        memcpy(tmpName, &data[shift], tmpLength*charSize);
        shift += tmpLength*charSize;

        tmpPointer = new float[tmpCount2*tmpJoint->data.matrixSize*floatSize];
        memcpy(tmpPointer, &data[shift], tmpCount2*tmpJoint->data.matrixSize*floatSize);

        if (!asAddAnimationToJoint(tmpJoint->data.name, tmpName, tmpPointer, tmpCount2))
          delete [] tmpPointer;

        shift += tmpCount2*tmpJoint->data.matrixSize*floatSize;

        tmpItem = animList.alGetFirstItem();
        while(tmpItem)
        {
          if (tmpItem->data == tmpName)
            break;

          tmpItem = tmpItem->next;
        }

        if (!tmpItem)
          animList.alAddItem()->data = tmpName;
      }
    }
  }

  return FINISH;
}

//=============================================================================

aItem<aJoint>* aSkeleton::asGetJointByName(aItem<aJoint>* jnt, const aString& name) const
{
  if (!jnt || (name.asGetLength() <= 0))
    return 0;

  aItem<aJoint>* tmpJoint = jnt,* tmpJoint2;

  while(tmpJoint)
  {
    if (tmpJoint->data.name == name)
      return tmpJoint;

    tmpJoint2 = asGetJointByName(tmpJoint->data.child.alGetFirstItem(), name);

    if (tmpJoint2)
      return tmpJoint2;

    tmpJoint = tmpJoint->next;
  }

  return 0;
}

//=============================================================================

aItem<aJoint>* aSkeleton::asAddJoint(aItem<aJoint>* parent)
{
  if (parent)
  {
    aItem<aJoint>* tmpJoint = parent->data.child.alAddItem();
    
    tmpJoint->data.parent = parent;

    return tmpJoint;
  }
  else
    return joints.alAddItem();
}

//=============================================================================

void aSkeleton::asCalculatePositionsByBindMatrix(aItem<aJoint>* jnt)
{
  if (!jnt)
    return;

  aItem<aJoint>* tmpJoint = jnt;
  aVector tmpVector;

  while(tmpJoint)
  {
    if (tmpJoint->data.parent)
    {
      tmpVector.avSet(tmpJoint->data.bindMatrix[12], tmpJoint->data.bindMatrix[13], tmpJoint->data.bindMatrix[14]);
      tmpVector = aAux::aaGetInstance().aaVVVXYZ2pos(tmpJoint->data.parent->data.bindIJK[0], tmpJoint->data.parent->data.bindIJK[1], tmpJoint->data.parent->data.bindIJK[2], tmpVector);
      tmpJoint->data.bindPosition = tmpVector + tmpJoint->data.parent->data.bindPosition;

      tmpJoint->data.bindIJK[0].avSet(tmpJoint->data.bindMatrix[0], tmpJoint->data.bindMatrix[1], tmpJoint->data.bindMatrix[2]);
      tmpJoint->data.bindIJK[1].avSet(tmpJoint->data.bindMatrix[4], tmpJoint->data.bindMatrix[5], tmpJoint->data.bindMatrix[6]);
      tmpJoint->data.bindIJK[2].avSet(tmpJoint->data.bindMatrix[8], tmpJoint->data.bindMatrix[9], tmpJoint->data.bindMatrix[10]);

      tmpJoint->data.bindIJK[0] = aAux::aaGetInstance().aaVVVXYZ2pos(tmpJoint->data.parent->data.bindIJK[0], tmpJoint->data.parent->data.bindIJK[1], tmpJoint->data.parent->data.bindIJK[2], tmpJoint->data.bindIJK[0]);
      tmpJoint->data.bindIJK[1] = aAux::aaGetInstance().aaVVVXYZ2pos(tmpJoint->data.parent->data.bindIJK[0], tmpJoint->data.parent->data.bindIJK[1], tmpJoint->data.parent->data.bindIJK[2], tmpJoint->data.bindIJK[1]);
      tmpJoint->data.bindIJK[2] = aAux::aaGetInstance().aaVVVXYZ2pos(tmpJoint->data.parent->data.bindIJK[0], tmpJoint->data.parent->data.bindIJK[1], tmpJoint->data.parent->data.bindIJK[2], tmpJoint->data.bindIJK[2]);
    }
    else
    {
      tmpJoint->data.bindPosition.avSet(tmpJoint->data.bindMatrix[12], tmpJoint->data.bindMatrix[13], tmpJoint->data.bindMatrix[14]);
      tmpJoint->data.bindIJK[0].avSet(tmpJoint->data.bindMatrix[0], tmpJoint->data.bindMatrix[1], tmpJoint->data.bindMatrix[2]);
      tmpJoint->data.bindIJK[1].avSet(tmpJoint->data.bindMatrix[4], tmpJoint->data.bindMatrix[5], tmpJoint->data.bindMatrix[6]);
      tmpJoint->data.bindIJK[2].avSet(tmpJoint->data.bindMatrix[8], tmpJoint->data.bindMatrix[9], tmpJoint->data.bindMatrix[10]);
    }

    asCalculatePositionsByBindMatrix(tmpJoint->data.child.alGetFirstItem());

    tmpJoint = tmpJoint->next;
  }
}

//=============================================================================

void aSkeleton::asGenerateStaticJointsList(aItem<aJoint>* jnt)
{
  if (!jnt)
    return;

  aItem<aJoint*>* tmpJoint;

  while(jnt)
  {
    tmpJoint = pubJoints.alGetFirstItem();
    while(tmpJoint)
    {
      if (tmpJoint->data->name == jnt->data.name)
        break;

      tmpJoint = tmpJoint->next;
    }

    if (!tmpJoint)
      pubJoints.alAddItem()->data = &jnt->data;

    asGenerateStaticJointsList(jnt->data.child.alGetFirstItem());

    jnt = jnt->next;
  }
}

//=============================================================================

void aSkeleton::asCalculateJoints(aItem<aJoint>* jnt)
{
  if (!jnt)
    return;

  aItem<aJoint>* tmpJoint = jnt;
  aVector tmpVector;

  while(tmpJoint)
  {
    if (tmpJoint->data.parent)
    {
      tmpVector.avSet(tmpJoint->data.currentMatrix[12], tmpJoint->data.currentMatrix[13], tmpJoint->data.currentMatrix[14]);
      tmpVector = aAux::aaGetInstance().aaVVVXYZ2pos(tmpJoint->data.parent->data.ijk[0], tmpJoint->data.parent->data.ijk[1], tmpJoint->data.parent->data.ijk[2], tmpVector);
      tmpJoint->data.position = tmpVector + tmpJoint->data.parent->data.position;

      tmpJoint->data.ijk[0].avSet(tmpJoint->data.currentMatrix[0], tmpJoint->data.currentMatrix[1], tmpJoint->data.currentMatrix[2]);
      tmpJoint->data.ijk[1].avSet(tmpJoint->data.currentMatrix[4], tmpJoint->data.currentMatrix[5], tmpJoint->data.currentMatrix[6]);
      tmpJoint->data.ijk[2].avSet(tmpJoint->data.currentMatrix[8], tmpJoint->data.currentMatrix[9], tmpJoint->data.currentMatrix[10]);

      tmpJoint->data.ijk[0] = aAux::aaGetInstance().aaVVVXYZ2pos(tmpJoint->data.parent->data.ijk[0], tmpJoint->data.parent->data.ijk[1], tmpJoint->data.parent->data.ijk[2], tmpJoint->data.ijk[0]);
      tmpJoint->data.ijk[1] = aAux::aaGetInstance().aaVVVXYZ2pos(tmpJoint->data.parent->data.ijk[0], tmpJoint->data.parent->data.ijk[1], tmpJoint->data.parent->data.ijk[2], tmpJoint->data.ijk[1]);
      tmpJoint->data.ijk[2] = aAux::aaGetInstance().aaVVVXYZ2pos(tmpJoint->data.parent->data.ijk[0], tmpJoint->data.parent->data.ijk[1], tmpJoint->data.parent->data.ijk[2], tmpJoint->data.ijk[2]);
    }
    else
    {
      tmpJoint->data.position.avSet(tmpJoint->data.currentMatrix[12], tmpJoint->data.currentMatrix[13], tmpJoint->data.currentMatrix[14]);
      tmpJoint->data.ijk[0].avSet(tmpJoint->data.currentMatrix[0], tmpJoint->data.currentMatrix[1], tmpJoint->data.currentMatrix[2]);
      tmpJoint->data.ijk[1].avSet(tmpJoint->data.currentMatrix[4], tmpJoint->data.currentMatrix[5], tmpJoint->data.currentMatrix[6]);
      tmpJoint->data.ijk[2].avSet(tmpJoint->data.currentMatrix[8], tmpJoint->data.currentMatrix[9], tmpJoint->data.currentMatrix[10]);
    }

    asCalculateJoints(tmpJoint->data.child.alGetFirstItem());

    tmpJoint = tmpJoint->next;
  }
}

//=============================================================================

void aSkeleton::asResetJointsToBind()
{
  aItem<aJoint*>* tmpJoint = pubJoints.alGetFirstItem();
  
  size_t magicSize = sizeof(float)*aJoint::matrixSize;

  while(tmpJoint)
  {
    memcpy(tmpJoint->data->currentMatrix, tmpJoint->data->bindMatrix, magicSize);
    tmpJoint = tmpJoint->next;
  }

  asCalculateJoints(joints.alGetFirstItem());
}

//=============================================================================

void aSkeleton::asCopyDataToCurrentMatrix()
{
  aItem<aJoint*>* tmpJoint = pubJoints.alGetFirstItem();
  
  while(tmpJoint)
  {
    tmpJoint->data->ajCopyDataToCurrentMatrix();
    tmpJoint = tmpJoint->next;
  }
}

//=============================================================================

void aSkeleton::asAddFactorToBindPositions()
{
  aItem<aJoint*>* tmpJoint = pubJoints.alGetFirstItem();
  
  while(tmpJoint)
  {
    tmpJoint->data->bindIJK[0] = tmpJoint->data->bindIJK[0]*float(factor);
    tmpJoint->data->bindIJK[1] = tmpJoint->data->bindIJK[1]*float(factor);
    tmpJoint->data->bindIJK[2] = tmpJoint->data->bindIJK[2]*float(factor);

    tmpJoint = tmpJoint->next;
  }
  asPrepareBindValues();
}

//=============================================================================

void aSkeleton::asPrepareBindValues()
{
  aItem<aJoint*>* tmpJoint = pubJoints.alGetFirstItem();
  
  while(tmpJoint)
  {
    tmpJoint->data->bindIJKValue[0] = tmpJoint->data->bindIJK[0].x*tmpJoint->data->bindIJK[0].x + tmpJoint->data->bindIJK[0].y*tmpJoint->data->bindIJK[0].y + tmpJoint->data->bindIJK[0].z*tmpJoint->data->bindIJK[0].z;
    tmpJoint->data->bindIJKValue[1] = tmpJoint->data->bindIJK[1].x*tmpJoint->data->bindIJK[1].x + tmpJoint->data->bindIJK[1].y*tmpJoint->data->bindIJK[1].y + tmpJoint->data->bindIJK[1].z*tmpJoint->data->bindIJK[1].z;
    tmpJoint->data->bindIJKValue[2] = tmpJoint->data->bindIJK[2].x*tmpJoint->data->bindIJK[2].x + tmpJoint->data->bindIJK[2].y*tmpJoint->data->bindIJK[2].y + tmpJoint->data->bindIJK[2].z*tmpJoint->data->bindIJK[2].z;

    tmpJoint = tmpJoint->next;
  }
}

//=============================================================================

aSkeleton::~aSkeleton()
{
}

//=============================================================================
